package org.budo.dubbo.registry.redis.util;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.budo.dubbo.registry.redis.AbstractBudoRedisRegistry;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.StringUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * @author limingwei2
 */
public class RegistryJedisUtil {
    private static final int DEFAULT_REDIS_PORT = 6379;

    private static final Logger log = LoggerFactory.getLogger(RegistryJedisUtil.class);

    public static Jedis getJedisResource(AbstractBudoRedisRegistry budoRedisRegistry) {
        try {
            JedisPool jedisPool = budoRedisRegistry.getJedisPool();
            Jedis jedis = jedisPool.getResource();
            return jedis;
        } catch (RuntimeException e) {
            URL thisUrl = budoRedisRegistry.getUrl();

            String message = "#30 getJedisResource error, url=" + thisUrl //
                    + ", host=" + getHost(budoRedisRegistry) //
                    + ", port=" + getPort(budoRedisRegistry) //
                    + ", timeout=" + getTimeout(budoRedisRegistry) //
                    + ", e=" + e;

            log.error(message);
            throw new RuntimeException(message, e);
        }
    }

    /**
     * 初始化 JedisPool
     */
    public static JedisPool initJedisPool(AbstractBudoRedisRegistry budoRedisRegistry) {
        JedisPool jedisPool = null;
        GenericObjectPoolConfig jedisPoolConfig = RegistryJedisUtil.jedisPoolConfig();

        String password = getPassword(budoRedisRegistry);
        String host = getHost(budoRedisRegistry);
        Integer port = getPort(budoRedisRegistry);
        Integer timeout = getTimeout(budoRedisRegistry);

        if (StringUtils.isEmpty(password)) {
            jedisPool = new JedisPool(jedisPoolConfig, //
                    host, //
                    port, //
                    timeout);
        } else {
            jedisPool = new JedisPool(jedisPoolConfig, //
                    host, //
                    port, //
                    timeout, //
                    password);
        }

        log.info("#68 init JedisPool, jedisPool=" + jedisPool + ", host=" + host + ", port=" + port);

        return jedisPool;
    }

    /**
     * redis 连接池
     */
    public static GenericObjectPoolConfig jedisPoolConfig() {
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

        poolConfig.setMinIdle(1);
        poolConfig.setMaxIdle(15);
        poolConfig.setMaxTotal(80);
        poolConfig.setMaxWaitMillis(10 * 1000);
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestWhileIdle(true);

        poolConfig.setTimeBetweenEvictionRunsMillis(600 * 1000);

        return poolConfig;
    }

    public static void returnResource(AbstractBudoRedisRegistry budoRedisRegistry, Jedis jedis) {
        returnResource(budoRedisRegistry.getJedisPool(), jedis);
    }

    @SuppressWarnings("deprecation")
    private static void returnResource(JedisPool jedisPool, Jedis jedis) {
        if (null != jedisPool && null != jedis) {
            jedisPool.returnResource(jedis);
        } else {
            close(jedis);
        }
    }

    public static void close(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }

    private static String getPassword(AbstractBudoRedisRegistry budoRedisRegistry) {
        return null == budoRedisRegistry.getUrl() ? null : budoRedisRegistry.getUrl().getPassword();
    }

    private static Integer getTimeout(AbstractBudoRedisRegistry budoRedisRegistry) {
        return null == budoRedisRegistry.getUrl() ? null : budoRedisRegistry.getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
    }

    public static Integer getPort(AbstractBudoRedisRegistry budoRedisRegistry) {
        if (null == budoRedisRegistry.getUrl()) {
            return null;
        }

        String address = budoRedisRegistry.getUrl().getAddress();
        int i = address.indexOf(':');
        if (i > 0) {
            return Integer.parseInt(address.substring(i + 1));
        }

        return DEFAULT_REDIS_PORT;
    }

    public static String getHost(AbstractBudoRedisRegistry budoRedisRegistry) {
        if (null == budoRedisRegistry.getUrl()) {
            return null;
        }

        String address = budoRedisRegistry.getUrl().getAddress();
        int i = address.indexOf(':');
        if (i > 0) {
            return address.substring(0, i);
        }

        return address;
    }
}